package pub.dsb.example.thread;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>
 *  https://leetcode-cn.com/problems/building-h2o/
 * </p>
 *
 * @author Yi
 * @version V1.0.0
 * @date 2020/12/31 14:04
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify By: {修改人} 2020/12/31 14:04
 * @modify reason: {方法名}:{原因}
 * ...
 * @since V1.0.0
 */
public class LC1117Test {
    public static void main(String[] args) {
        //H2O h2O = new H2O();
        H2OF2 h2O = new H2OF2();
        String h2o = "HHHHHHHHHHOHHOHHHHOOHHHOOOOHHOOHOHHHHHOOHOHHHOOOOOOHHHHHHHHH";
        for (int i = 0; i < h2o.length(); i++) {
            char ch = h2o.charAt(i);
            switch (ch) {
                case 'O':
                    new Thread(() -> {
                        try {
                            h2O.oxygen();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }).start();
                    break;
                case 'H':
                    new Thread(() -> {
                        try {
                            h2O.hydrogen();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }).start();
                    break;
                default:
                    break;
            }
        }
    }
}

class H2OF2 {

    private Semaphore oSemaphore = new Semaphore(1);
    private Semaphore hSemaphore = new Semaphore(2);
    private CyclicBarrier cb = new CyclicBarrier(3, () -> {
        oSemaphore.release(1);
        hSemaphore.release(2);

    });

    public H2OF2() {

    }

    //public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
    public void hydrogen() throws InterruptedException {
        hSemaphore.acquire(1);
        // releaseHydrogen.run() outputs "H". Do not change or remove this line.
        //releaseHydrogen.run();
        System.out.print("H");
        try {
            cb.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }

    }

    //public void oxygen(Runnable releaseOxygen) throws InterruptedException {
    public void oxygen() throws InterruptedException {
        oSemaphore.acquire(1);
        // releaseOxygen.run() outputs "O". Do not change or remove this line.
        //releaseOxygen.run();
        System.out.print("O");
        try {
            cb.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

class H2O {

    private AtomicInteger oCounter = new AtomicInteger(0);
    private AtomicInteger hCounter = new AtomicInteger(0);
    private CyclicBarrier cb = new CyclicBarrier(3, () -> {
        hCounter.set(0);
        oCounter.set(0);
    });

    public H2O() {

    }

    //public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
    public void hydrogen() throws InterruptedException {
        while (hCounter.addAndGet(1) > 2) {

        }
        // releaseHydrogen.run() outputs "H". Do not change or remove this line.
        //releaseHydrogen.run();
        System.out.print("H");
        try {
            cb.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }

    }

    //public void oxygen(Runnable releaseOxygen) throws InterruptedException {
    public void oxygen() throws InterruptedException {
        while (oCounter.addAndGet(1) > 1) {

        }

        // releaseOxygen.run() outputs "O". Do not change or remove this line.
        //releaseOxygen.run();
        System.out.print("O");
        try {
            cb.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}